package in

import (
	"fmt"
	"math/rand"
	"strings"
	"sync"
	"time"

	"github.com/patrickmn/go-cache"
)

var (
	CacheInMemory = cache.New(50*time.Minute, 100*time.Minute)
	DataSets      = make(KeySet)
	DataSetsId    = make(map[string]int)

	MemLastInfo struct {
		LastConnectStr string
		LastTbStr      string
		LastGrep       G
		MemPage        int
		MemPageLen     int
		LastCacheKey   string
	}
	MemGloBalLock = new(sync.Mutex)
)

func MemoryLastInfo(conn, table string, grep G, page, pageLen int) {
	MemGloBalLock.Lock()
	defer MemGloBalLock.Unlock()
	ColorL("Tmp Cache DataBottle Info:", conn, table, page, pageLen)
	MemLastInfo.LastConnectStr = conn
	MemLastInfo.LastTbStr = table
	MemLastInfo.MemPageLen = pageLen
	MemLastInfo.MemPage = page
	MemLastInfo.LastGrep = grep
}

func SaveInCache(name string, datas Datas) {
	initId := (len(DataSetsId) + 1) * 1000000
	DataSetsId[name] = initId
	for no, data := range datas {
		data["nodeid"] = initId + no + 1
	}

	CacheInMemory.Set(name, datas, cache.NoExpiration)
	DataSets[name] = true
	MemLastInfo.LastCacheKey = name
}

func MemoryGetCacheId(name string) int {
	if v, ok := DataSetsId[name]; ok {
		return v
	}
	return -1
}

func MemoryGet(name string) (visnodes Datas) {
	id := MemoryGetCacheId(name)
	if id == -1 {
		return
	}
	vs, ok := CacheInMemory.Get(name)
	if ok {
		// ks := vs.(Datas).Keys().SortedList()
		visnodes = vs.(Datas).VisNodes()
	}
	return
}

func MemoryAll() (visnodes Datas) {

	for name := range DataSets {
		id := MemoryGetCacheId(name)
		if id == -1 {
			continue
		}
		t := MemoryGet(name)
		visnodes = append(visnodes, t...)
	}
	return
}

func (datas Datas) VisNodes() (visnodes Datas) {
	allCount := len(datas)
	for _, data := range datas {
		labelM := data.String()

		visnodes = append(visnodes, G{
			"id":    data["nodeid"],
			"x":     (rand.Float32() - .5) * float32(allCount),
			"y":     (rand.Float32() - .5) * float32(allCount),
			"label": labelM,
			"title": string(data.ToJson()),
			"data":  data,
		})
	}
	return
}

func MemoryListSet() (visnodes Datas) {
	for name := range DataSets {
		id := MemoryGetCacheId(name)
		if id == -1 {
			continue
		}

		visnodes = append(visnodes, G{
			"id":    id,
			"label": name,
			"title": name,
		})
	}
	return
}

func MemoryKeySearch(key string) (datas Datas) {
	key = strings.ToUpper(strings.TrimSpace(key))
	for k := range DataSets {
		if v, ok := CacheInMemory.Get(k); ok {
			datasOne := v.(Datas)
			for _, data := range datasOne {
				test := strings.ToUpper(fmt.Sprintf("%v", data))
				if strings.Contains(test, key) {
					datas = append(datas, data)
				} else {
					ColorL(key, test)
				}
			}

		}
	}

	return datas.VisNodes()
}

func MemoryDictSearch(filter G) (datas Datas) {
	for k := range DataSets {
		if v, ok := CacheInMemory.Get(k); ok {
			datasOne := v.(Datas)
			for _, data := range datasOne {
				testOk := true
				for k := range filter {
					if ch, ok := data[k]; ok {
						if strings.Contains(fmt.Sprint(ch), fmt.Sprint(filter[k])) {
							continue
						}
					}
					testOk = false
					break
				}
				if testOk {
					datas = append(datas, data)
				}
			}
		}
	}
	return datas.VisNodes()
}

func MemoryFastSearch(filter G) (datas Datas) {
	for k := range DataSets {
		if v, ok := CacheInMemory.Get(k); ok {
			datasOne := v.(Datas)
			for _, data := range datasOne {
				testOk := true
				for k := range filter {
					if ch, ok := data[k]; ok {
						if ch == data[k] {
							continue
						}
					}
					testOk = false
					break
				}
				if testOk {
					datas = append(datas, data)
				}
			}
		}
	}
	return datas.VisNodes()
}

func MemoryKeys(setName ...string) (ds []string) {
	names := make(KeySet)
	if len(setName) == 0 {
		for k := range DataSets {
			if dv, ok := CacheInMemory.Get(k); ok {

				for no, dg := range dv.(Datas) {
					for kname := range dg {
						names[kname] = true
					}
					if no > 3 {
						break
					}

				}
			}
		}
	} else {
		for _, na := range setName {
			if dv, ok := CacheInMemory.Get(na); ok {
				for _, dg := range dv.(Datas) {
					for kname := range dg {
						names[kname] = true
					}
					break
				}
			}
		}

	}
	return names.SortedList()
}

func MemorySetPageLen(len int) {
	MemGloBalLock.Lock()
	defer MemGloBalLock.Unlock()
	MemLastInfo.MemPageLen = len
}

func MemoryNextPage(handDatas func(bottle BottleInterface, datas Datas, err error)) {
	MemGloBalLock.Lock()
	MemLastInfo.MemPage++
	MemGloBalLock.Unlock()
	SearchByLastSearchInfo(func(bottle BottleInterface, oper *Oper) {
		datas := bottle.Query(oper)
		handDatas(bottle, datas, nil)
	}, func(err error) {
		handDatas(nil, nil, err)

	})

}
